<?php

require_once 'HTMLPurifier/ChildDef.php';

/**
 * Definition for tables
 */
class HTMLPurifier_ChildDef_Table extends HTMLPurifier_ChildDef
{
	var $allow_empty = false;
	var $type = 'table';
	var $elements = array('tr' => true, 'tbody' => true, 'thead' => true,
		'tfoot' => true, 'caption' => true, 'colgroup' => true, 'col' => true);
	function HTMLPurifier_ChildDef_Table() {}
	function validateChildren($tokens_of_children, $config, &$context) {
		if (empty($tokens_of_children)) return false;
		
		// this ensures that the loop gets run one last time before closing
		// up. It's a little bit of a hack, but it works! Just make sure you
		// get rid of the token later.
		$tokens_of_children[] = false;
		
		// only one of these elements is allowed in a table
		$caption = false;
		$thead   = false;
		$tfoot   = false;
		
		// as many of these as you want
		$cols	= array();
		$content = array();
		
		$nesting = 0; // current depth so we can determine nodes
		$is_collecting = false; // are we globbing together tokens to package
								// into one of the collectors?
		$collection = array(); // collected nodes
		$tag_index = 0; // the first node might be whitespace,
							// so this tells us where the start tag is
		
		foreach ($tokens_of_children as $token) {
			$is_child = ($nesting == 0);
			
			if ($token === false) {
				// terminating sequence started
			} elseif ($token->type == 'start') {
				$nesting++;
			} elseif ($token->type == 'end') {
				$nesting--;
			}
			
			// handle node collection
			if ($is_collecting) {
				if ($is_child) {
					// okay, let's stash the tokens away
					// first token tells us the type of the collection
					switch ($collection[$tag_index]->name) {
						case 'tr':
						case 'tbody':
							$content[] = $collection;
							break;
						case 'caption':
							if ($caption !== false) break;
							$caption = $collection;
							break;
						case 'thead':
						case 'tfoot':
							// access the appropriate variable, $thead or $tfoot
							$var = $collection[$tag_index]->name;
							if ($$var === false) {
								$$var = $collection;
							} else {
								// transmutate the first and less entries into
								// tbody tags, and then put into content
								$collection[$tag_index]->name = 'tbody';
								$collection[count($collection)-1]->name = 'tbody';
								$content[] = $collection;
							}
							break;
						 case 'colgroup':
							$cols[] = $collection;
							break;
					}
					$collection = array();
					$is_collecting = false;
					$tag_index = 0;
				} else {
					// add the node to the collection
					$collection[] = $token;
				}
			}
			
			// terminate
			if ($token === false) break;
			
			if ($is_child) {
				// determine what we're dealing with
				if ($token->name == 'col') {
					// the only empty tag in the possie, we can handle it
					// immediately
					$cols[] = array_merge($collection, array($token));
					$collection = array();
					$tag_index = 0;
					continue;
				}
				switch($token->name) {
					case 'caption':
					case 'colgroup':
					case 'thead':
					case 'tfoot':
					case 'tbody':
					case 'tr':
						$is_collecting = true;
						$collection[] = $token;
						continue;
					default:
						if ($token->type == 'text' && $token->is_whitespace) {
							$collection[] = $token;
							$tag_index++;
						}
						continue;
				}
			}
		}
		
		if (empty($content)) return false;
		
		$ret = array();
		if ($caption !== false) $ret = array_merge($ret, $caption);
		if ($cols !== false)	foreach ($cols as $token_array) $ret = array_merge($ret, $token_array);
		if ($thead !== false)   $ret = array_merge($ret, $thead);
		if ($tfoot !== false)   $ret = array_merge($ret, $tfoot);
		foreach ($content as $token_array) $ret = array_merge($ret, $token_array);
		if (!empty($collection) && $is_collecting == false){
			// grab the trailing space
			$ret = array_merge($ret, $collection);
		}
		
		array_pop($tokens_of_children); // remove phantom token
		
		return ($ret === $tokens_of_children) ? true : $ret;
		
	}
}

